﻿using System.Collections.Concurrent;

namespace DesignModeConsole.创建型.单例模式;

public interface ILogger
{
    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    void Log(string message);
}

/// <summary>
/// 日志服务（不做单例模式，那么会出现当前文件已经被其他线程进程使用）
/// </summary>
public class Logger : ILogger
{
    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    public void Log(string message)
    {
        var path = AppContext.BaseDirectory + "/log.txt";
        if (!File.Exists(path))
        {
            File.Exists(path);
        }

        File.WriteAllText(path, message);
    }
}

/// <summary>
/// 日志服务 （虽然使用了锁，但是多个地方使用会创建多个对象，该锁只能保证一个对象的时候，按照顺序执行）
/// </summary>
public class Logger1 : ILogger
{
    private object _lock = new object();

    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    public void Log(string message)
    {
        lock (_lock)
        {
            var path = AppContext.BaseDirectory + "/log.txt";
            if (!File.Exists(path))
            {
                File.Exists(path);
            }

            File.WriteAllTextAsync(path, message);
        }
    }
}

/// <summary>
/// 单例类 饿汉式：缺点不支持延迟加载
/// </summary>
public class Logger2 : ILogger
{
    private static readonly Logger2 instance = new Logger2();
    private object _lock = new object();

    private Logger2() { }

    public static Logger2 GetInstance()
    {
        return instance;
    }

    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    public void Log(string message)
    {
        lock (_lock)
        {
            var path = AppContext.BaseDirectory + "/log.txt";
            if (!File.Exists(path))
            {
                File.Exists(path);
            }

            File.WriteAllText(path, message);
        }
    }
}

/// <summary>
/// 懒汉式 缺点：不支持高并发
/// </summary>
public class Logger3 : ILogger
{
    private static Logger3 _instance;
    private static object _obj = new object();

    private object _writelock = new object();

    private Logger3() { }

    public static Logger3 GetInstance()
    {
        lock (_obj)
        {
            if (_instance == null)
                _instance = new Logger3();

            return _instance;
        }
    }

    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    public void Log(string message)
    {
        lock (_writelock)
        {
            var path = AppContext.BaseDirectory + "/log.txt";
            if (!File.Exists(path))
            {
                File.Exists(path);
            }

            File.WriteAllText(path, message);
        }
    }
}

/// <summary>
/// 双重检测  支持延迟加载、支持高并发
/// </summary>
public class Logger4 : ILogger
{
    private static Logger4? _instance;
    private static object _obj = new object();
    private object _writelock = new object();

    private Logger4() { }

    public static Logger4 GetInstance()
    {
        if (_instance == null)
        {
            lock (_obj)
            {
                if (_instance == null)
                    _instance = new Logger4();
            }
        }

        return _instance;
    }

    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    public void Log(string message)
    {
        lock (_writelock)
        {
            var path = AppContext.BaseDirectory + "/log.txt";
            if (!File.Exists(path))
            {
                File.Exists(path);
            }

            File.WriteAllText(path, message);
        }
    }
}

/// <summary>
/// 通过嵌套类实现完全懒汉式
/// </summary>
public sealed class Logger5 : ILogger
{
    private Logger5() { }

    public static Logger5 GetInstance()
    {
        return Nested._instance;
    }

    /// <summary>
    /// 使用内部类+静态构造函数实现延迟初始化
    /// </summary>
    private class Nested
    {
        static Nested() { }

        internal static readonly Logger5 _instance = new Logger5();
    }

    private object _writelock = new object();

    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    public void Log(string message)
    {
        lock (_writelock)
        {
            var path = AppContext.BaseDirectory + "/log.txt";
            if (!File.Exists(path))
            {
                File.Exists(path);
            }

            File.WriteAllText(path, message);
        }
    }
}

/// <summary>
/// 通过lazy实现懒汉式 推荐
/// </summary>
public sealed class Logger7 : ILogger
{
    /// <summary>
    /// Lazy类型会确保 Logger7 的实例仅在第一次访问 Instance 属性时创建（即惰性初始化）。
    /// </summary>
    private static readonly Lazy<Logger7> _lazy = new Lazy<Logger7>(() => new Logger7());

    /// <summary>
    /// 私有构造函数保证外部无法直接实例化
    /// </summary>
    private Logger7() { }

    /// <summary>
    /// 提供一个公共的只读属性用于获取单例实例
    /// </summary>
    /// <returns></returns>
    public static Logger7 GetInstance()
    {
        // lazy.Value 在首次访问时调用指定的委托来创建 SingletonClass 实例，之后每次访问都会返回相同的实例。
        return _lazy.Value;
    }

    private readonly object _writeLock = new object();

    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    public void Log(string message)
    {
        lock (_writeLock)
        {
            var path = AppContext.BaseDirectory + "/log.txt";
            if (!File.Exists(path))
            {
                File.Exists(path);
            }

            File.WriteAllText(path, message);
        }
    }
}

/// <summary>
/// 线程内唯一实例
/// </summary>
public sealed class Logger6 : ILogger
{
    private Logger6() { }

    //借助一个字典来存储对象，其中key是线程ID value是对象
    //这样子就可以做到不同的线程对应不同的对象，同一个线程对应一个对象
    private static readonly ConcurrentDictionary<int, Logger6> _instances =
        new ConcurrentDictionary<int, Logger6>();

    public static Logger6 GetInstance()
    {
        var currentThreadId = Environment.CurrentManagedThreadId;
        _instances.TryAdd(currentThreadId, new Logger6());
        return _instances[currentThreadId];
    }

    private object _writelock = new object();

    /// <summary>
    /// 添加日志
    /// </summary>
    /// <param name="message"></param>
    public void Log(string message)
    {
        lock (_writelock)
        {
            var path = AppContext.BaseDirectory + "/log.txt";
            if (!File.Exists(path))
            {
                File.Exists(path);
            }

            File.WriteAllText(path, message);
        }
    }
}